#ifndef SC_ADB_H
#define SC_ADB_H


#include "common.h"

// stdbool.h是C标准函数库中一个常用的头文件。它定义了一个布尔类型，于C99中加入
#include <stdbool.h>

// inttypes.h是标准C函数库的头文件，提供整数输入的各种转换宏,C99
#include <inttypes.h>

#include "adb_device.h"
#include "util/intr.h"

// 自定义标准输出
#define SC_ADB_NO_STDOUT (1 << 0)
// 自定义错误输出
#define SC_ADB_NO_STDERR (1 << 1)
// 自定义日志输出
#define SC_ADB_NO_LOGERR (1 << 2)
// 自定义全部都输出
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)

/* 
获取adb所在的执行路径：获取环境变量ADB，如果没有此环境变量将直接返回adb
@return 返回常量指针，指向adb命令或路径用于直接执行adb命令    
*/
const char *
sc_adb_get_executable(void);

// 安卓设备的连接方式
enum sc_adb_device_selector_type {
    // 下面的任意一种方式均可用于连接
    SC_ADB_DEVICE_SELECT_ALL,
    // 通过Android设备序列号连接
    SC_ADB_DEVICE_SELECT_SERIAL,
    // 通过USB线连接
    SC_ADB_DEVICE_SELECT_USB,
    // 通过wifi连接
    SC_ADB_DEVICE_SELECT_TCPIP,
};

/* 安卓设备选择器，即用什么方式和哪个Android设备进行连接 */
struct sc_adb_device_selector {
    // 设备连接方式
    enum sc_adb_device_selector_type type;
    
    // Android设备的序列号，命令行指定或由环境变量指定。type=SC_ADB_DEVICE_SELECT_SERIAL时必传
    const char *serial;
};

/*
执行终端命令，并忽略终端的输出
@param argv 待执行的终端命令
@param flags 输出标记
@return 线程ID
*/
sc_pid
sc_adb_execute(const char *const argv[], unsigned flags);

/* 
执行命令 adb start-server 启动adb服务
@param intr 辅助可中断器
@param flags 本方法中命令没有任何输出，直接传0即可
@return 执行成功返回true,否则返回false
*/
bool
sc_adb_start_server(struct sc_intr *intr, unsigned flags);

/// @brief 执行命令 adb kill-server
/// @param intr 中断器
/// @param flags 本方法中命令没有任何输出，直接传0即可
/// @return 执行成功返回true,否则返回false
/// @see { https://www.baidu.com 模拟文档}
bool
sc_adb_kill_server(struct sc_intr *intr, unsigned flags);

bool
sc_adb_forward(struct sc_intr *intr, const char *serial, uint16_t local_port,
               const char *device_socket_name, unsigned flags);

bool
sc_adb_forward_remove(struct sc_intr *intr, const char *serial,
                      uint16_t local_port, unsigned flags);

bool
sc_adb_reverse(struct sc_intr *intr, const char *serial,
               const char *device_socket_name, uint16_t local_port,
               unsigned flags);

bool
sc_adb_reverse_remove(struct sc_intr *intr, const char *serial,
                      const char *device_socket_name, unsigned flags);

/**
 * 将文件上传到android设备
 * @param intr
 * @param serial Android设备的序列号
 * @param local  PC上的文件路径
 * @param remote Android设备上的文件路径
 * @param flags
 */
bool
sc_adb_push(struct sc_intr *intr, const char *serial, const char *local,
            const char *remote, unsigned flags);

bool
sc_adb_install(struct sc_intr *intr, const char *serial, const char *local,
               unsigned flags);

/**
 * Execute `adb tcpip <port>`
 */
bool
sc_adb_tcpip(struct sc_intr *intr, const char *serial, uint16_t port,
             unsigned flags);

/**
 * Execute `adb connect <ip_port>`
 *
 * `ip_port` may not be NULL.
 */
bool
sc_adb_connect(struct sc_intr *intr, const char *ip_port, unsigned flags);

/**
 * Execute `adb disconnect [<ip_port>]`
 *
 * If `ip_port` is NULL, execute `adb disconnect`.
 * Otherwise, execute `adb disconnect <ip_port>`.
 */
bool
sc_adb_disconnect(struct sc_intr *intr, const char *ip_port, unsigned flags);

/**
 * Execute `adb devices` and parse the result to select a device
 * @param intr 可中断器
 * @param selector 安卓设备选择方式
 * @param flags 
 * @param out_device 选中的设备
 * @return Return true if a single matching device is found, and write it to out_device.
 */
bool
sc_adb_select_device(struct sc_intr *intr,
                     const struct sc_adb_device_selector *selector,
                     unsigned flags, struct sc_adb_device *out_device);

/**
 * Execute `adb getprop <prop>`
 */
char *
sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
               unsigned flags);

/**
 * 尝试检索到Android设备的IP地址.
 * Attempt to retrieve the device IP
 * @param intr
 * @param serial android设备的序列号
 * @param flags 默认传0
 * @return Return the IP as a string of the form "xxx.xxx.xxx.xxx", to be freed by the
 * caller, or NULL on error.
 *
 * 当unsigned独立使用时,默认为unsigned int ，即无符号整数
 */
char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);

#endif
